#include "hrsystem.h"

using namespace std;
using namespace rational;

HRSystem::HRSystem(int numberOfCompanies)
	: _Companies(numberOfCompanies)
{
	if (numberOfCompanies <=0 )
	{
		throw InvalidInputExcpetion();
	}
	for(int i=0 ;i<numberOfCompanies; ++i)
	{
		shared_ptr<Company> currCompany(new Company(i));
		_Companies.push_back(currCompany);
	}
}

HRSystem::~HRSystem()
{
}

void CheckEmployeeId(int id)
{
	if (id<=0)
	{
		throw EmployeeIdIllegal();
	}
}

shared_ptr<Company> HRSystem::GetCompany(int companyId) const
{
	if (companyId<0 || companyId>=_Companies.Size())
	{
		throw CompanyIndexOutOfRange();
	}
	shared_ptr<Company> res = _Companies[companyId];
	if (res.get()==NULL)
	{
		throw CompanyDoesNotExist();
	}
	return res;
}

shared_ptr<Employee> HRSystem::GetEmployee(int employee) const
{
	try
	{
		CheckEmployeeId(employee);
		shared_ptr<Employee> res = _Employees.FindKey(employee);
		return res;
	}
	catch (const KeyNotInTreeException&)
	{
		throw EmployeeIdNotDefined();
	}
}

void HRSystem::HireEmployee(int employeeId,
							const rational::Rational &salary,
							int companyId)
{
	try
	{
		if (salary<=0)
		{
			throw InvalidSalary();
		}
		CheckEmployeeId(employeeId);
		shared_ptr<Employee> employee(new Employee(employeeId, companyId, salary));
		shared_ptr<Company> comp = GetCompany(companyId);
		_Employees.InsertKey(employeeId, employee);
		comp->HireEmployee(employee);
	}
	catch (const KeyAlreadyInTreeException&)
	{
		throw EmployeeIdRedifined();
	}
}

void HRSystem::FireEmployee(int employeeId, int companyId)
{
	try
	{
		shared_ptr<Employee> employee = GetEmployee(employeeId);
		shared_ptr<Company> company = GetCompany(companyId);
		company->FireEmployee(employeeId, employee->GetSalary());
		_Employees.DeleteKey(employeeId);
	}
	catch (const KeyNotInTreeException&)
	{
		throw FailureException();
	}
}

Rational HRSystem::GetSalary(int employeeId) const
{
	shared_ptr<Employee> employee = GetEmployee(employeeId);
	shared_ptr<Company> company = GetCompany(employee->GetEmployer());
	return company->GetRealSalary(*employee);
}

int HRSystem::GetEmployer(int employeeId) const
{
	return GetEmployee(employeeId)->GetEmployer();
}

Rational HRSystem::GetMedianSalary(int companyId) const
{
	return GetCompany(companyId)->GetMedianSalary();
}

Rational HRSystem::GetHeighestSalary(int companyId) const
{
	return GetCompany(companyId)->GetMaxSalary();
}

void HRSystem::UpdateSalaries(int companyId, const rational::Rational& factor)
{
	GetCompany(companyId)->UpdateSalary(factor);
}

void HRSystem::Merger(int buyingCompany, int sellingCompany)
{
	shared_ptr<Company> buyingPtr = GetCompany(buyingCompany);
	shared_ptr<Company> sellingPtr = GetCompany(sellingCompany);
	buyingPtr->Merge(*sellingPtr);
	_Companies[sellingCompany].reset();
}
